#include "../kernel.h"
#include "boot_ap.S.h"

pdir_entry_t boot_ap_vpd[PAGEDIR_COUNT] __attribute__((aligned(PAGE_SIZE)));

volatile struct lcpu_t lcpus[LAPIC_COUNT];
volatile struct boot_ap_info_t boot_ap_info;
int apic_inv_map[LAPIC_COUNT];

extern pdir_entry_t init_vpd[PAGEDIR_COUNT];

int
lcpu_init(void)
{
	 memmove(KADDR(BOOT_AP_ENTRY), boot_ap_entry, PAGE_SIZE);
	 memmove(KADDR(BOOT_AP_GDT), boot_ap_gdt, PAGE_SIZE);
	 memmove(KADDR(BOOT_AP_GDT_DESC), boot_ap_gdt_desc, PAGE_SIZE);
	 memmove(boot_ap_vpd, init_vpd, PAGE_SIZE);
	 boot_ap_vpd[0] = boot_ap_vpd[PAGEDIR_IDX(KBASE)];
	 int i;
	 for (i = 0; i != sysconf.lcpu_count; ++ i)
	 {
		  if (i != sysconf.lcpu_boot)
		  {
			   boot_ap_info.id = i;
			   spl_init(&boot_ap_info.success_lock);
			   spl_acquire(&boot_ap_info.success_lock);
			   spl_init(&lcpus[i].start_lock);
			   spl_acquire(&lcpus[i].start_lock);
			   kprintf("Starting ap %d\n", i);
			   lapic_startap(lcpus[i].apic_id, BOOT_AP_ENTRY);
			   spl_acquire(&boot_ap_info.success_lock);
			   spl_release(&boot_ap_info.success_lock);
		  }
	 }
}

static void
boot_ap_main(void)
{
	 kprintf("lapic...");
	 lapic_init_ap();
	 kprintf("vmem...");
	 vmem_init_ap(envs[procs[cur_proc_id()].env].vpt);
	 kprintf("intr...");
	 intr_init_ap();
	 kprintf("task...");
	 task_init_ap();
	 kprintf("ok\n");

	 spl_release(&boot_ap_info.success_lock);
	 spl_acquire(&lcpus[cur_lcpu()].start_lock);

	 kprintf("LCPU %d Jump into user!\n", cur_lcpu());
	 jump_ulib((void *)((struct elf_t *)user_lib)->e_entry, (void *)0,
 			   read_eflags() | FL_IF | FL_IOPL_3);
}

void
boot_ap_c_entry(void)
{
	 __asm __volatile("movl %0, %%esp" ::
					  /* -16 for safty, check the asm of the function */
					  "r" (PROC_KSTACK_TOP(lcpus[boot_ap_info.id].idle_pid)));
	 boot_ap_main();
}
